package com.ctshk.rpc.order.bus.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.ApprovalStatus;
import com.ctshk.common.enums.IsDeletedCode;
import com.ctshk.common.enums.OrderPaymentStatus;
import com.ctshk.common.enums.OrderRefundStatus;
import com.ctshk.common.enums.SystemBusinessType;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.enums.bus.BusConst;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.service.support.BaseService;
import com.ctshk.common.utils.Assist;
import com.ctshk.common.utils.OperateNumberGenerateUtil;
import com.ctshk.rpc.bus.dto.BusProductDTO;
import com.ctshk.rpc.bus.service.IBusProductService;
import com.ctshk.rpc.finance.json.AccountJson;
import com.ctshk.rpc.finance.req.bill.BillAddRefundReq;
import com.ctshk.rpc.finance.req.onaccount.RollBackQuotaReq;
import com.ctshk.rpc.finance.service.IFinanceBillService;
import com.ctshk.rpc.finance.service.IFinanceOnAccountCurrencyQuotaService;
import com.ctshk.rpc.iotc.req.OperateBankRefundReq;
import com.ctshk.rpc.iotc.req.OperatePromotionRefundReq;
import com.ctshk.rpc.iotc.service.IOperateBankPreferenceService;
import com.ctshk.rpc.iotc.service.IOperatePromotionService;
import com.ctshk.rpc.order.bus.entity.BusOrder;
import com.ctshk.rpc.order.bus.entity.BusOrderCollection;
import com.ctshk.rpc.order.bus.entity.BusOrderRefund;
import com.ctshk.rpc.order.bus.mapper.BusOrderCollectionMapper;
import com.ctshk.rpc.order.bus.mapper.BusOrderMapper;
import com.ctshk.rpc.order.bus.mapper.BusOrderRefundMapper;
import com.ctshk.rpc.order.bus.mapper.BusOrderTouristMapper;
import com.ctshk.rpc.order.bus.req.BusOrderRefundApprovalItemReq;
import com.ctshk.rpc.order.bus.req.BusOrderRefundApprovalReq;
import com.ctshk.rpc.order.bus.service.IBusOrderRefundService;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.service.IMainDataCurrencyService;
import com.ctshk.rpc.system.service.ISysUserService;
import com.ctshk.rpc.workflow.dto.ApprovalCheckDTO;
import com.ctshk.rpc.workflow.service.ISysApprovalService;

/**
 * <p>
 * 巴士退款记录 服务实现类
 * </p>
 *
 * @author 彭柳霖
 * @since 2021-02-24
 */
@DubboService
public class BusOrderRefundServiceImpl extends ServiceImpl<BusOrderRefundMapper, BusOrderRefund> implements IBusOrderRefundService, BaseService {

    @Autowired
    private BusOrderRefundMapper busOrderRefundMapper;
    
    @DubboReference
    ISysApprovalService sysApprovalService;
    
    @Autowired
    BusOrderMapper busOrderMapper;
    
    @DubboReference
    IFinanceBillService iFinanceBillService;
    
    @DubboReference
    ISysUserService sysUserService;
    
    @DubboReference
    IMainDataCurrencyService iMainDataCurrencyService;
    
    @DubboReference
    IBusProductService busProductService;
    
    @Autowired
    BusOrderTouristMapper busOrderTouristMapper;
    
    @Autowired
    BusOrderCollectionMapper busOrderCollectionMapper;
    
    @DubboReference
    IOperatePromotionService operatePromotionService;
    
    @DubboReference
    IOperateBankPreferenceService operateBankPreferenceService;
    
    @DubboReference
    IFinanceOnAccountCurrencyQuotaService financeOnAccountCurrencyQuotaService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result delete(Long refundId, Long userId) {
        BusOrderRefund busOrderRefund = busOrderRefundMapper.selectById(refundId);
        if(Objects.isNull(busOrderRefund)){
            return Result.failed(SystemError.BUS_ORDER_9007);
        }

        if (busOrderRefund.getStatus() != OrderRefundStatus.AUDIT_FAILED.getCode()) {
            // 审批失败状态的退款记录才可以删除
            throw new BusinessException(SystemError.BUS_ORDER_9015);
        }

        busOrderRefund.setIsDeleted(IsDeletedCode.NO.getCode());
        busOrderRefund.setGmtModified(LocalDateTime.now());
        busOrderRefund.setModifiedId(userId);
        busOrderRefundMapper.updateById(busOrderRefund);
        return Result.success();
    }
    
    /**
     * 巴士取消订单审批
     * @param req
     * @return
     */
    @Transactional
    @Override
    public Result<Void> refundApproval(BusOrderRefundApprovalReq req, TokenUser tokenUser) {
    	//巴士订单
    	BusOrder busOrder = busOrderMapper.assertExistById(req.getBusinessId());
    	//巴士产品
    	BusProductDTO busProductDTO = busProductService.queryDetail(busOrder.getBusId());
    	//巴士订单退款记录列表
    	List<BusOrderRefund> busOrderRefundList = busOrderRefundMapper.selectListByKey("order_id", busOrder.getId());
    	//巴士订单退款记录审批的金额
    	Map<Long, BigDecimal> refundAmountMap = Assist.forEachToMap(req.getItemList(), BusOrderRefundApprovalItemReq::getRefundId, BusOrderRefundApprovalItemReq::getRefundAmount);
    	
    	//审批
    	ApprovalCheckDTO checkDto = sysApprovalService.check(req.getApprovalId(), getTokenUserId(tokenUser),
                req.getApprovalStatus(), req.getComments()).ok();
    	if (checkDto == null || !checkDto.getIsFinish()) {
    		return newResult();
    	}
    	
    	OrderRefundStatus orderRefundFlowStatus = null;
    	//是否审批通过
    	boolean isReviewYes = ApprovalStatus.REVIEW_YES.getCode() == req.getApprovalStatus();
        boolean callBack = false;
    	
    	//审批通过
    	if (isReviewYes) {
    		orderRefundFlowStatus = OrderRefundStatus.AUDIT_SUCCESSFUL;
            
            busOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_CANCEL.getCode());
        	busOrder.setCancelStatus(ApprovalStatus.REVIEW_YES.getCode());
        	
        	//回滚已售座位数
        	int touristNum = busOrderTouristMapper.selectCountByKey("order_id", busOrder.getId());
        	if (touristNum > 0) {
        		busProductService.rollbackSold(busOrder.getBusId(), touristNum, busOrder.getEffectiveTime(), tokenUser.getId());
        	}
        	
        } else if (ApprovalStatus.REVIEW_NO.getCode() == req.getApprovalStatus()) {  //审批不通过
        	orderRefundFlowStatus = OrderRefundStatus.AUDIT_FAILED;
        	busOrder.setCancelStatus(ApprovalStatus.REVIEW_NO.getCode());
        } else {  //撤回
        	busOrder.setCancelStatus(null);
        	callBack = true;
        }
    	
    	//更新巴士订单退款记录
    	if (Assist.isNotEmpty(busOrderRefundList)) {
    		BigDecimal hkdRefundedAmount = BigDecimal.ZERO;
    		for (BusOrderRefund busOrderRefund : busOrderRefundList) {
    			if (callBack) {
    				busOrderRefundMapper.deleteById(busOrderRefund.getId());
    			} else {
    				fillUpdateEntity(busOrderRefund);
    				busOrderRefund.setStatus(orderRefundFlowStatus.getCode());
//    				busOrderRefund.setRefundAmount(refundAmountMap.get(busOrderRefund.getId()));
    				busOrderRefund.setApprovalAmount(refundAmountMap.get(busOrderRefund.getId()));
    				
    				//审批通过
    		    	if (isReviewYes) {
    		    		BigDecimal hkdApprovalAmount = Assist.multiply(busOrderRefund.getApprovalAmount(), busOrderRefund.getExchangeRate());
    		    		hkdRefundedAmount = Assist.add(hkdRefundedAmount, hkdApprovalAmount);
    		    	}
    		    	
    		    	busOrderRefundMapper.updateById(busOrderRefund);
    			}
			}
    		
    		busOrder.setRefundedAmount(Assist.setScaleIntegerUp(hkdRefundedAmount));
    	}
    	
    	//更新巴士订单
    	fillUpdateEntity(busOrder, tokenUser);
    	busOrderMapper.updateById(busOrder);
    	
    	//审批通过
    	if (isReviewYes) {
    		//优惠相关处理
            refundToDiscounts(busOrder, getTokenUserId(tokenUser), busOrderRefundList);
            
            //收款记录列表
            List<BusOrderCollection> collectionEntityList = busOrderCollectionMapper.selectListByKey("order_id", busOrder.getId());
            //收款记录列表，key：收款方式ID
            Map<Long, BusOrderCollection> collectionEntityMap = Assist.forEachToMap(collectionEntityList, BusOrderCollection::getCollectionWayId);
            
    		//退款对接账务中心
            refundToFinance(busOrder, busOrderRefundList, getTokenUserId(tokenUser), busProductDTO, collectionEntityMap);
    	}
    	
    	return newResult();
    }
    
    /**
     * 确认退款(财务-内部调用)
     * @param refundNumber
     * @return
     */
    @Override
    public Result<Void> confirmRefund(String refundNumber, Long userId) {
    	validateNotBlank(refundNumber);
    	
    	BusOrderRefund entity = busOrderRefundMapper.assertExistSelectOneByKey("refund_number", refundNumber);
    	
    	fillUpdateEntityUserId(entity, userId);
    	entity.setStatus(ApprovalStatus.REFUND_SUCCESS.getCode());
    	
    	busOrderRefundMapper.updateById(entity);
    	
    	return newResult();
    }
    
    /**
     * 退款对接账务中心
     */
    private void refundToFinance(BusOrder orderEntity, List<BusOrderRefund> refundList, Long userId, BusProductDTO busProductDTO
    		, Map<Long, BusOrderCollection> collectionEntityMap) {
    	if (Assist.isEmpty(refundList)) {
    		return;
    	}
    	
    	//销售人员信息
    	UserDTO userDTO = Assist.ifNotNullFn(orderEntity.getSalesmanId(), sysUserService::queryCacheUser);
    	
    	//退款参数列表
    	List<BillAddRefundReq> addCallReqList = new ArrayList<>();
    	
    	for (BusOrderRefund refundEntity : refundList) {
    		//挂账、内部挂账、推广码、银联优惠、积分走销账
			if (BusConst.PAY_WAY_ID_ACCOUNTS.equals(refundEntity.getRefundWayId())
					|| BusConst.PAY_WAY_ID_ACCOUNTS_INNER.equals(refundEntity.getRefundWayId())
					|| BusConst.PAY_WAY_ID_PROMOTION_CODE.equals(refundEntity.getRefundWayId())
					|| BusConst.PAY_WAY_ID_BANK_DISCOUNTS.equals(refundEntity.getRefundWayId())
					|| BusConst.PAY_WAY_ID_INTEGRAL.equals(refundEntity.getRefundWayId())) {
				RollBackQuotaReq quotaCallReq = fillRollBackQuotaReq(refundEntity, orderEntity, busProductDTO, userDTO, userId);
				
				BusOrderCollection collectionEntity = collectionEntityMap.get(refundEntity.getRefundWayId());
				if (collectionEntity == null) {
					throw new BusinessException(SystemError.BUS_ORDER_9024);
				}
				quotaCallReq.setCollectionNumber(collectionEntity.getCollectionNumber());
				
				financeOnAccountCurrencyQuotaService.rollBackQuota(quotaCallReq).ok();
			} else {  //其余退款方式走退款
				BillAddRefundReq addCallReq = fillBillAddRefundReq(refundEntity, orderEntity, busProductDTO, userDTO, userId);
				addCallReqList.add(addCallReq);
			}
		}
    	
    	//退款
    	if (Assist.isNotEmpty(addCallReqList)) {
    		iFinanceBillService.addRefund(addCallReqList).ok();
    	}
	}
    
    /**
     * 退款，优惠相关处理
     */
    private void refundToDiscounts(BusOrder orderEntity, Long userId, List<BusOrderRefund> busOrderRefundList) {
    	List<BusOrderCollection> collectionEntityList = busOrderCollectionMapper.selectListByKey("order_id", orderEntity.getId()); 
    	if (Assist.isNotEmpty(collectionEntityList)) {
    		for (BusOrderCollection collectionEntity : collectionEntityList) {
    			if (BusConst.PAY_WAY_ID_PROMOTION_CODE.equals(collectionEntity.getCollectionWayId())) {  //推广码
    				//回滚推广码
    				refundPromotionCode(orderEntity, userId);
        		} else if (BusConst.PAY_WAY_ID_BANK_DISCOUNTS.equals(collectionEntity.getCollectionWayId())) {  //银联优惠
        			//回滚银行优惠
        			refundBankPreference(orderEntity, userId, collectionEntity);
        		} else if (BusConst.PAY_WAY_ID_INTEGRAL.equals(collectionEntity.getCollectionWayId())) {  //积分
        			
        		} else {
        			continue;
        		}
    			
    			//创建优惠的退款记录
    			BusOrderRefund refundEntity = newCreateEntityUserId(BusOrderRefund.class, null, userId);
    			fillData(refundEntity, orderEntity, collectionEntity);
    			busOrderRefundMapper.insert(refundEntity);
    			
    			busOrderRefundList.add(refundEntity);
			}
    	}
    }
    
    
    
    /**
     * 封装产品名称
     */
    private String packProductName(BusProductDTO dto) {
    	if (dto == null)
    		return null;
    	return packProductName(dto.getBoardingStationName(), dto.getAlightingStationName());
    }
    
    /**
     * 封装产品名称
     */
    private String packProductName(String boardingStationName, String alightingStationName) {
    	return Assist.join(boardingStationName, " - ", alightingStationName);
	}
    
    /**
     * 回滚推广码 
     */
    private void refundPromotionCode(BusOrder busOrder, Long userId) {
    	OperatePromotionRefundReq callReq = new OperatePromotionRefundReq();
    	callReq.setId(busOrder.getCouponId());
    	callReq.setTotalPaidIn(busOrder.getOrderAmount());
    	callReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
    	callReq.setRelationId(busOrder.getBusId());
    	callReq.setDiscountObjectId(null);
    	callReq.setChannelId(Assist.toLong(busOrder.getSource()));
    	operatePromotionService.refund(callReq, createFakeTokenUser(userId)).ok();
    }
    
    /**
     * 回滚银行优惠
     */
    private void refundBankPreference(BusOrder busOrder, Long userId, BusOrderCollection collectionEntity) {
    	OperateBankRefundReq callReq = new OperateBankRefundReq();
    	callReq.setId(collectionEntity.getUnionpayDiscountId());
    	callReq.setRelationId(busOrder.getBusId());
    	callReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
    	callReq.setRefundTotalPaidIn(busOrder.getOrderAmount());
    	callReq.setCardNumber(collectionEntity.getPayer());
    	callReq.setDiscountObjectId(null);
    	callReq.setChannelId(Assist.toLong(busOrder.getSource()));
    	operateBankPreferenceService.refundUpdate(callReq, createFakeTokenUser(userId));
    }
    
    private void fillData(BusOrderRefund entity, BusOrder busOrder, BusOrderCollection collectionEntity) {
		entity.setOrderId(busOrder.getId());
		entity.setStandardAmount(collectionEntity.getStandardAmount());
		entity.setRefundNumber(OperateNumberGenerateUtil.generateRefundNumber(LocalDateTime.now()));
		entity.setCurrencyId(collectionEntity.getCurrencyId());
		entity.setCurrency(collectionEntity.getCurrency());
		entity.setRefundAmount(collectionEntity.getCollectionAmount());
		entity.setRefundWayId(collectionEntity.getCollectionWayId());
		entity.setRefundWay(collectionEntity.getCollectionWay());
		entity.setRefundAccount(collectionEntity.getPayer());
		entity.setRefundReason(null);
		entity.setRemark(null);
		entity.setStatus(OrderRefundStatus.AUDIT_SUCCESSFUL.getCode());
		entity.setRejectReason(null);
		entity.setApprovalAmount(collectionEntity.getCollectionAmount());
		entity.setExchangeRate(collectionEntity.getExchangeRate());
	}
    
    private BillAddRefundReq fillBillAddRefundReq(BusOrderRefund refundEntity, BusOrder orderEntity, BusProductDTO busProductDTO, UserDTO userDTO
    		, Long userId) {
    	BillAddRefundReq callReq = new BillAddRefundReq();
		callReq.setBillNumber(refundEntity.getRefundNumber());
        callReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
        callReq.setCollectionAmount(refundEntity.getRefundAmount());
        callReq.setCurrencyId(refundEntity.getCurrencyId());
        callReq.setCurrencyName(refundEntity.getCurrency());
        callReq.setExchangeRate(refundEntity.getExchangeRate().doubleValue());
        callReq.setRefundTime(refundEntity.getGmtCreate());
        callReq.setSaleOrderNumber(orderEntity.getOrderNumber());
        callReq.setSaleOrderId(orderEntity.getId());
        callReq.setProductId(Assist.asList(orderEntity.getBusId()));
        callReq.setProductName(packProductName(busProductDTO));
		callReq.setResourceInfo(Assist.asList(callReq.getProductName()));
        callReq.setProductNumber(busProductDTO.getProductCode());
        callReq.setRefundTypeId(refundEntity.getRefundWayId());
        callReq.setRefundType(refundEntity.getRefundWay());
        
        if (userDTO != null) {
        	callReq.setSaleUserId(userDTO.getId());
        	callReq.setSaleUserName(userDTO.getFullName());
        	callReq.setSaleDeptId(userDTO.getDeptId());
        }
        callReq.setUserId(userId);
        
        AccountJson refundAccountJson = new AccountJson();
        refundAccountJson.setCardNumber(refundEntity.getRefundAccount());
        callReq.setRefundAccountJson(refundAccountJson);
        
        return callReq;
	}
    
    private RollBackQuotaReq fillRollBackQuotaReq(BusOrderRefund refundEntity, BusOrder orderEntity, BusProductDTO busProductDTO, UserDTO userDTO
    		, Long userId) {
    	RollBackQuotaReq callReq = new RollBackQuotaReq();
    	callReq.setOrderId(orderEntity.getId());
    	callReq.setCollectionNumber(null);
    	callReq.setRefundNumber(refundEntity.getRefundNumber());
    	callReq.setAmount(refundEntity.getRefundAmount());
    	callReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
    	callReq.setUserId(userId);
    	return callReq;
	}
}
